Dijkstra’s algorithm for weighted Graphs [PyPlot]¶
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
# %matplotlib inline
graph = {'A': {'B':2, 'C':3},
'B': {'C':2, 'D':2},
'C': {'D':3, 'E':2},
'D': {'F':3},
'E': {'D':1,'F':1},
'F': {}}
Graph = nx.DiGraph()
for node in graph:
Graph.add_nodes_from(node)
for edge, weight in graph[node].items():
Graph.add_edge(node,edge, weight=weight)
pos = { 'A': [0.00, 0.50], 'B': [0.25, 0.75],
'C': [0.25, 0.25], 'D': [0.75, 0.75],
'E': [0.75, 0.25], 'F': [1.00, 0.50]}
labels = nx.get_edge_attributes(Graph,'weight')
nx.draw(Graph, pos, with_labels=True)
nx.draw_networkx_edge_labels(Graph, pos, edge_labels=labels)
nx.draw_networkx(Graph,pos)
plt.show()
from heapq import heapify, heappop, heappush
class priority_queue():
def __init__(self):
self.queue = list()
heapify(self.queue)
self.index = dict()
def push(self, priority, label):
if label in self.index:
self.queue = [(w,l) for w,l in self.queue if l!=label]
heapify(self.queue)
heappush(self.queue, (priority, label))
self.index[label] = priority
def pop(self):
if self.queue:
return heappop(self.queue)
def __contains__(self, label):
return label in self.index
def __len__(self):
return len(self.queue)
def dijkstra(graph, start, end):
inf = float('inf')
known = set()
priority = priority_queue()
path = {start: start}
for vertex in graph:
if vertex == start:
priority.push(0, vertex)
else:
priority.push(inf, vertex)
last = start
while last != end:
(weight, actual_node) = priority.pop()
if actual_node not in known:
for next_node in graph[actual_node]:
upto_actual = priority.index[actual_node]
upto_next = priority.index[next_node]
to_next = upto_actual + graph[actual_node][next_node]
if to_next < upto_next:
priority.push(to_next, next_node)
print("Found shortcut from %s to %s" % (actual_node, next_node))
print ("\tTotal length up so far: %i" % to_next)
path[next_node] = actual_node
last = actual_node
known.add(actual_node)
return priority.index, path
Test¶
dist, path = dijkstra(graph, 'A', 'F')
# dist = {'A': 0, 'B': 2, 'C': 3, 'D': 4, 'E': 5, 'F': 6}
# path = {'A': 'A', 'B': 'A', 'C': 'A', 'D': 'B', 'E': 'C', 'F': 'E'}
def reverse_path(path, start, end):
progression = [end]
while progression[-1] != start:
progression.append(path[progression[-1]])
return progression[::-1]
print(reverse_path(path, 'A', 'F'))
# ['A', 'C', 'E', 'F']